using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using BF.UI;
using Newtonsoft.Json.Linq;
using UnityEngine;

namespace BF
{
    /// <summary>
    /// 弹窗管理
    /// </summary>
    public static class DialogManager
    {
        private const string TAG = "DialogManager";
        /// <summary>
        /// 弹窗预制体储存路径，相对于Resources目录
        /// </summary>
        private const string PREFAB_PATH = "Dialog/";
        /// <summary>
        /// 弹窗基类的Type
        /// </summary>
        private static readonly Type D_TYPE = typeof(Dialog);
        /// <summary>
        /// 弹窗打开
        /// </summary>
        public static event Action<Dialog> onDialogOpen;
        /// <summary>
        /// 弹窗关闭
        /// </summary>
        public static event Action<Dialog> onDialogClose;
        /// <summary>
        /// 弹窗预制体
        /// </summary>
        private static Dictionary<string, GameObject> _dialogPrefabs = new Dictionary<string, GameObject>();
        /// <summary>
        /// 弹窗缓存
        /// </summary>
        private static Dictionary<string, Dialog> _showCache = new Dictionary<string, Dialog>();


        static DialogManager()
        {
            DialogRoot.Init();
        }

        public static GameObject LoadPrefab(Type dialogType)
        {
            if (!dialogType.IsSubclassOf(D_TYPE))
            {
                throw new ArgumentException($"Type:{dialogType.Name} is not Dialog");
            }
            string name = dialogType.Name;
            return LoadPrefab(name);
        }

        /// <summary>
        /// 加载弹窗预制体
        /// </summary>
        public static GameObject LoadPrefab<T>() where T : Dialog
        {
            string name = typeof(T).Name;
            return LoadPrefab(name);
        }

        public static GameObject LoadPrefab(string dialogName)
        {
            GameObject prefab = Resources.Load<GameObject>($"{PREFAB_PATH}{dialogName}");
            if (prefab == null)
            {
                Log.E(TAG, $"Dialog prefab is null: {dialogName}");
                return null;
            }

            if (_dialogPrefabs.ContainsKey(dialogName))
            {
                _dialogPrefabs[dialogName] = prefab;
            }
            else
            {
                _dialogPrefabs.Add(dialogName, prefab);
            }
            return prefab;
        }

        /// <summary>
        /// 获取打开的弹窗
        /// </summary>
        public static Dialog GetDialog(Type dialogType)
        {
            if (!dialogType.IsSubclassOf(D_TYPE))
            {
                throw new ArgumentException($"Type:{dialogType.Name} is not Dialog");
            }
            string name = dialogType.Name;
            return GetDialog(name);
        }

        /// <summary>
        /// 获取打开的弹窗
        /// </summary>
        public static T GetDialog<T>() where T : Dialog
        {
            string name = typeof(T).Name;
            Dialog d = GetDialog(name);
            return d == null ? null : d as T;
        }

        /// <summary>
        /// 获取打开的弹窗
        /// </summary>
        public static Dialog GetDialog(string dialogName)
        {
            if (_showCache.ContainsKey(dialogName))
            {
                return _showCache[dialogName];
            }
            return null;
        }

        public static void Close(Type dialogType)
        {
            if (!dialogType.IsSubclassOf(D_TYPE))
            {
                throw new ArgumentException($"Type:{dialogType.Name} is not Dialog");
            }
            string name = dialogType.Name;
            Close(name);
        }

        /// <summary>
        /// 关闭弹窗
        /// </summary>
        public static void Close<T>() where T : Dialog
        {
            string name = typeof(T).Name;
            Close(name);
        }

        /// <summary>
        /// 关闭弹窗
        /// </summary>
        public static void Close(string dialogName)
        {
            if (_showCache.ContainsKey(dialogName))
            {
                _showCache[dialogName].Close();
            }
        }


        public static void CloseAll()
        {
            var keys = new List<string>(_showCache.Keys);
            for (int i = keys.Count - 1; i >= 0; --i)
            {
                _showCache[keys[i]].Close();
            }
        }

        public static void DestroyAll()
        {
            List<string> keys = new List<string>(_showCache.Keys);
            for (int i = keys.Count - 1; i >= 0; --i)
            {
                try
                {
                    Dialog dialog = _showCache[keys[i]];
                    UnityEngine.Object.Destroy(dialog.gameObject);
                }
                catch (Exception e)
                {
                    Debug.LogError(e);
                }
            }
            _showCache.Clear();
        }

        /// <summary>
        /// 释放Prefab资源
        /// </summary>
        public static void UnloadPrefab<T>() where T : Dialog
        {
            string name = typeof(T).Name;
            UnloadPrefab(name);
        }

        /// <summary>
        /// 释放Prefab资源
        /// </summary>
        public static void UnloadPrefab(Type dialogType)
        {
            if (!dialogType.IsSubclassOf(D_TYPE))
            {
                throw new ArgumentException($"Type:{dialogType.Name} is not Dialog");
            }
            string name = dialogType.Name;
            UnloadPrefab(name);
        }

        /// <summary>
        /// 释放Prefab资源
        /// </summary>
        public static void UnloadPrefab(string dialogName)
        {
            if (_dialogPrefabs.ContainsKey(dialogName))
            {
                GameObject prefab = _dialogPrefabs[dialogName];
                //Resources.UnloadAsset(prefab); //此行会报错UnloadAsset may only be used on individual assets and can not be used on GameObject's / Components / AssetBundles or GameManagers
                _dialogPrefabs.Remove(dialogName);
            }
        }

        /// <summary>
        /// 释放Prefab资源
        /// </summary>
        public static void UnloadAllPrefab()
        {
            foreach (var kv in _dialogPrefabs)
            {
                //Resources.UnloadAsset(kv.Value); //此行会报错UnloadAsset may only be used on individual assets and can not be used on GameObject's / Components / AssetBundles or GameManagers
            }
            _dialogPrefabs.Clear();
        }

        /// <summary>
        /// 打开弹窗
        /// </summary>
        public static T Open<T>() where T : Dialog
        {
            string name = typeof(T).Name;
            Dialog dialog = Open(name);
            return dialog == null ? null : dialog as T;
        }

        /// <summary>
        /// 打开弹窗
        /// </summary>
        public static Dialog Open(Type dialogType)
        {
            if (!dialogType.IsSubclassOf(D_TYPE))
            {
                throw new ArgumentException($"Type:{dialogType.Name} is not Dialog");
            }
            string name = dialogType.Name;
            return Open(name);
        }

        /// <summary>
        /// 打开弹窗
        /// </summary>
        public static Dialog Open(string dialogName)
        {
            Dialog dialog = null;

            if (_showCache.ContainsKey(dialogName) && _showCache[dialogName] != null)
            {
                dialog = _showCache[dialogName];
            }
            else
            {
                GameObject prefab = LoadPrefab(dialogName);
                if (prefab == null)
                {
                    return null;
                }
                dialog = UnityEngine.Object.Instantiate(prefab).GetComponent<Dialog>();
                InitDialog(dialog, _dialogPrefabs[dialogName].name);
            }

            dialog.gameObject.SetActive(true);

            onDialogOpen?.Invoke(dialog);

            dialog.SetOnClose(onDialogClose);
            if (dialog.isUnloadPrefabOnShow)
            {
                UnloadPrefab(dialogName);
            }

            return dialog;
        }


        private static Dialog InitDialog(Dialog dialog, string name)
        {
            dialog.gameObject.name = name;
            dialog.transform.SetParent(DialogRoot.rectTransform, false);
            dialog.rectTransform.anchorMin = Vector2.zero;
            dialog.rectTransform.anchorMax = Vector2.one;
            dialog.rectTransform.pivot = 0.5f * Vector2.one;
            dialog.rectTransform.offsetMin = Vector2.zero;
            dialog.rectTransform.offsetMax = Vector2.zero;
            dialog.rectTransform.localPosition = Vector3.zero;
            dialog.rectTransform.localRotation = Quaternion.identity;
            dialog.rectTransform.localScale = Vector3.one;
            dialog.canvas.overrideSorting = true;
            dialog.canvas.sortingOrder = dialog.GetCanvasOrder();



            dialog.SetOnDestroy((it) =>
            {
                if (_showCache.ContainsKey(it.gameObject.name))
                {
                    _showCache.Remove(it.gameObject.name);
                }
            });

            if (_showCache.ContainsKey(name))
            {
                _showCache[name] = dialog;
            }
            else
            {
                _showCache.Add(name, dialog);
            }

            return dialog;
        }

        /// <summary>
        /// 弹窗是否打开
        /// </summary>
        public static bool IsDialogShowing(string dialogName)
        {
            if (_showCache.Count == 0)
            {
                return false;
            }

            if (string.IsNullOrEmpty(dialogName))
            {
                return _showCache.Any(pair => IsDialogShowing(pair.Value));
            }

            if (!_showCache.ContainsKey(dialogName))
            {
                return false;
            }

            return IsDialogShowing(_showCache[dialogName]);
        }

        private static bool IsDialogShowing(Dialog dialog)
        {
            return dialog != null && dialog.IsDialogShowing();
        }

        public static bool IsDialogShowing<T>() where T : Dialog
        {
            string name = typeof(T).Name;
            return IsDialogShowing(name);
        }

        public static bool IsDialogShowing(Type dialogType)
        {
            if (!dialogType.IsSubclassOf(D_TYPE))
            {
                throw new ArgumentException($"Type:{dialogType.Name} is not Dialog");
            }
            string name = dialogType.Name;
            return IsDialogShowing(name);
        }

        /// <summary>
        /// 是否有弹窗打开
        /// </summary>
        public static bool IsDialogShowing()
        {
            return IsDialogShowing(string.Empty);
        }

        /// <summary>
        /// 弹窗是否显示在最前面
        /// </summary>
        /// <param name="ignoreDialogs">忽略的弹窗</param>
        public static bool IsDialogOnTop<T>(HashSet<string> ignoreDialogs = null) where T : Dialog
        {
            string name = typeof(T).Name;
            return IsDialogOnTop(name, ignoreDialogs);
        }

        /// <summary>
        /// 弹窗是否显示在最前面
        /// </summary>
        /// <param name="ignoreDialogs">忽略的弹窗</param>
        public static bool IsDialogOnTop(string dialogName, HashSet<string> ignoreDialogs = null)
        {
            if (!IsDialogShowing(dialogName))
            {
                return false;
            }
            int top = _showCache.Max(it => (it.Value.IsDialogShowing() && (ignoreDialogs == null || !ignoreDialogs.Contains(it.Key)) ? it.Value.canvas.sortingOrder : -1));
            return _showCache[dialogName].canvas.sortingOrder == top;
        }

        [System.Diagnostics.Conditional("DEBUG")]
        public static void ExportCurrntMessage()
        {
            StringBuilder stringBuilder = new StringBuilder();
            foreach(var d in _dialogPrefabs)
            {
                if (d.Value != null)
                {
                    stringBuilder.Append("dialog name:" + d.Key + "\n");
                }
                else
                {
                    Log.W(TAG, $"ExportCurrntMessage {d.Key} is null");
                }
            }
            Log.I(TAG, stringBuilder.ToString());
        }
    }
}
